﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GbmpPlanView.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GbmpModelViewExternalDataId.h"
#include "GbmpModelViewUtil.h"
#include "GbmpPlanViewInput.h"
#include "GcmpBuiltInParameterDefinitions.h"
#include "ICalculator.h"
#include "ICalculatorCollection.h"
#include "ICopyStrategyReporter.h"
#include "IDocument.h"
#include "IElementParentReporter.h"
#include "IExternalDataComponent.h"
#include "ILevel.h"
#include "IModelView.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IWorkPlane.h"
#include "IUserCoordinateSystem.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;


CREATE_DEBUG_MODE(DebugEnableDeepPlaneCutable, L"开启深度裁剪面裁剪功能", gcmp::DebugModeGroup::DMGT_VIEW, L"GDMPLab", L"2023-12-20", L"开启此mode则深度裁剪面具有裁剪功能。");

DEFINE_MODEL_VIEW_BASE_METHODS(GbmpPlanView)

DBOBJECT_DATA_DEFINE(GbmpPlanView)
{
    m_pOwnerElement = nullptr;
}

GbmpPlanView* GbmpPlanView::Create(const GbmpPlanViewInput& input)
{
    ILevel* pLevel = input.Level;
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pLevel, L"pLevel为空",L"GDMPLab",L"2024-03-30");

    Vector3d viewOrigin(0, 0, pLevel->GetElevation());
    IModelView* pModelView = GbmpModelViewUtil::CreateModelView(input.Document, input.Name, BuiltInViewType::TwoDimensional,
        input.ViewDirection, viewOrigin, input.RightDirection, input.UpDirection);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    pModelView->SetUserDataId(input.ViewType);

    pModelView->AddTopPlane(input.TopOffset);
    pModelView->AddCutPlane(input.CutOffset);
    pModelView->AddBottomPlane(input.BottomOffset);
    if (DEBUG_MODE(DebugEnableDeepPlaneCutable))
        pModelView->AddDeepPlane(input.DeepOffset, true);
    else
        pModelView->AddDeepPlane(input.DeepOffset, false);

    pModelView->SetContourLineCalculationThreshold(0);

    if (input.HasRectViewport)
    {
        pModelView->CreateDefaultRectViewport(input.RectViewportWidth / 2.0, input.RectViewportWidth / 2.0, input.RectViewportHeight / 2.0, input.RectViewportHeight / 2.0);
    }

    IUserCoordinateSystem* pUCS = IUserCoordinateSystem::Create(input.Document, input.Name, viewOrigin, input.RightDirection, input.UpDirection);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pUCS, L"pUCS为空",L"GDMPLab",L"2024-03-30");

    GbmpPlanView* pPlanView = GbmpPlanView::RegisterExternalData(pModelView);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pPlanView, L"pPlanView为空",L"GDMPLab",L"2024-03-30");

    pPlanView->SetWorkLevelId(pLevel->GetOwnerElement()->GetElementId());
    pLevel->AddAssociatedPlanViewId(pModelView->GetElementId());
    pPlanView->SetUserViewTypeName(input.ViewType);

    pModelView->BindUserCoordinateSystem(pUCS->GetElementId());

    return pPlanView;
}

GbmpPlanView* GbmpPlanView::Get(IModelView* pModelView)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    if (IExternalDataComponent * pExternalDataComponent = pModelView->GetExternalDataComponent())
    {
        IExternalData* pData = pExternalDataComponent->FindExternalData(MODEL_VIEW_EXTERNAL_DATA_ID);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pData, L"pData为空",L"GDMPLab",L"2024-03-30");
        return quick_cast<GbmpPlanView>(pData);
    }
    return nullptr;
}

const GbmpPlanView* GbmpPlanView::Get(const IModelView* pModelView)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    if (const IExternalDataComponent * pExternalDataComponent = pModelView->GetExternalDataComponent())
    {
        const IExternalData* pData = pExternalDataComponent->FindExternalData(MODEL_VIEW_EXTERNAL_DATA_ID);
        DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pData, L"pData为空",L"GDMPLab",L"2024-03-30");
        return quick_cast<const GbmpPlanView>(pData);
    }
    return nullptr;
}

GbmpPlanView* GbmpPlanView::RegisterExternalData(IModelView* pModelView)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<GbmpPlanView> opPlanView = NEW_AS_OWNER_PTR(GbmpPlanView);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opPlanView, L"opPlanView为空",L"GDMPLab",L"2024-03-30");

    opPlanView->SetOwnerElement(pModelView);

    GbmpPlanView* pPlanView = opPlanView.get();
    if (IExternalDataComponent * pExternalDataComponent = pModelView->GetExternalDataComponent())
    {
        pExternalDataComponent->RegisterExternalData(MODEL_VIEW_EXTERNAL_DATA_ID, TransferOwnership(opPlanView));
    }
    return pPlanView;
}

bool GbmpPlanView::SetWorkLevelId(ElementId workLevelId)
{
    SetWorkLevelId__(workLevelId);

    // 平面视图设置工作楼层，同时设置相应工作平面
    IModelView* pModelView = quick_cast<IModelView>(GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    IWorkPlane* pWorkPlane = quick_cast<IWorkPlane>(pModelView->GetDocument()->GetElement(pModelView->GetWorkPlaneId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pWorkPlane, L"pWorkPlane为空",L"GDMPLab",L"2024-03-30");
    pWorkPlane->SetReferencedPlaneId(workLevelId);

    return true;
}

void GbmpPlanView::UpdateForWeakParentDeletion(const std::set<ElementId>& deletedElementIds)
{
}

void GbmpPlanView::ReportParents(IElementParentReporter& reporter) const
{
    reporter.ReportStrong(GetWorkLevelId());
}

DECLARE_CALCULATOR_CREATOR(ModelViewOriginCalculator);
void GbmpPlanView::GetCalculators(ICalculatorCollection * calculators) const
{
    ADD_CALCULATOR(ModelViewOriginCalculator, GetDocument(), GetModelView()->GetOriginRdId());
}

void GbmpPlanView::ReportParameterDefinitions(std::vector<int>* pParamDefIds) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDefIds, L"pParamDefIds为空",L"GDMPLab",L"2024-03-30");
    pParamDefIds->push_back(PARAMETER_ID(GbmpViewWorkLevelBuiltInParameter));
}

OwnerPtr<IParameter> GbmpPlanView::GetNativeParameter(int paramDefId) const
{
    if (paramDefId == PARAMETER_ID(GbmpViewWorkLevelBuiltInParameter))
    {
        //OwnerPtr<IParameter> pParam = NEW_AS_OWNER_PTR(Parameter, GetDocument(),
            //ParameterStorageType::ElementId, false, false, true, 
            //PARAMETER_UID(GbmpViewWorkLevelBuiltInParameter), ParameterProcessType::GeneralInput);
        ParameterAttributes pa = {false, false, true};
        OwnerPtr<IParameter> pParam = IParameter::CreateParameter(GetDocument(), 
            ParameterStorageType::ElementId, pa, PARAMETER_UID(GbmpViewWorkLevelBuiltInParameter), 
            ParameterProcessType::GeneralInput);
        pParam->SetValueAsElementId(GetWorkLevelId());
        return TransferOwnership(pParam);
    }
    return nullptr;
}

bool GbmpPlanView::SetNativeParameter(const IParameter *param, std::wstring* errorMsg/* = nullptr*/)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMPLab",L"2024-03-30");

    if (param->GetParameterDefinitionId() == PARAMETER_ID(GbmpViewWorkLevelBuiltInParameter))
    {
        SetWorkLevelId(param->GetValueAsElementId());
        return true;
    }
    return false;
}

bool GbmpPlanView::IsParameterModifiable(int paramDefId) const
{
    return true;
}

void GbmpPlanView::Report(const ICopyContext& copyContext, ICopyStrategyReporter& reporter) const
{
    reporter.ReportToCopy(GetOwnerElementId());
    reporter.ReportToKeep(GetWorkLevelId());
}

IDocument* GbmpPlanView::GetDocument() const
{
    return m_pOwnerElement ? m_pOwnerElement->GetDocument() : nullptr;
}

ElementId GbmpPlanView::GetOwnerElementId() const
{
    return m_pOwnerElement ? m_pOwnerElement->GetElementId() : ElementId::InvalidID;
}

NdbObject* GbmpPlanView::GetTopOwnerObject() const
{
    if (!GetDocument())
        return nullptr;

    return quick_cast<NdbObject>(GetDocument()->GetElement(GetOwnerElementId()));
}
